package com.cx.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.cx.constant.RoleConstant;
import com.cx.constant.UserStatus;
import com.cx.dto.UserDTO;
import com.cx.dto.UserPageDTO;
import com.cx.mapper.MenuMapper;
import com.cx.mapper.ProjectMapper;
import com.cx.mapper.RoleMapper;
import com.cx.mapper.UserMapper;
import com.cx.pojo.LoginUserDetails;
import com.cx.pojo.Menu;
import com.cx.pojo.Project;
import com.cx.pojo.User;
import com.cx.properties.JwtProperties;
import com.cx.service.ProjectService;
import com.cx.service.UserService;
import com.cx.util.JwtUtil;
import com.cx.util.PageResult;
import com.cx.util.ResultUtil;
import com.cx.vo.JobAndCountVO;
import com.cx.vo.MenuVO;
import com.cx.vo.PermissionsVO;
import com.cx.vo.UserVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import javafx.animation.Animation;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;


@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    private final AuthenticationManager authenticationManager;
    private final RedisTemplate redisTemplate;
    private final JwtProperties jwtProperties;
    private final RoleMapper roleMapper;
    private final MenuMapper menuMapper;
    private final ProjectMapper projectMapper;

    @Override
    public ResultUtil<UserVO> login(UserDTO userDTO) {
        // 获取AuthenticationManager对象进行用户认证
        // 将用户名和密码封装成Authentication对象
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                userDTO.getUsername(), userDTO.getPassword());
        // authenticationManager.authenticate(authenticationToken)：会执行UserDetailsServiceImpl.loadUserByUsername()方法进行登录认证
        Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        // 身份有误，认证失败
        if (Objects.isNull(authentication)) {
            throw new RuntimeException("认证失败");
        }
        // 认证通过，获取userId生成token
        LoginUserDetails loginUserDetails = (LoginUserDetails) authentication.getPrincipal();
        // 生成token
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", loginUserDetails.getUser().getId());
        String token = JwtUtil.create(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims);
        // 将user对象存入redis中
        redisTemplate.opsForValue().set("user:login:" + loginUserDetails.getUser().getId(), loginUserDetails);
        // 获取用户的menu
        List<Menu> menus = menuMapper.getMenuByUserId(loginUserDetails.getUser().getId());
        List<MenuVO> menuVOS = new ArrayList<>(menus.size());
        menus.forEach(menu -> {
            MenuVO menuVo = BeanUtil.copyProperties(menu, MenuVO.class);
            menuVOS.add(menuVo);
        });
        UserVO userVo = BeanUtil.copyProperties(loginUserDetails.getUser(), UserVO.class);
        userVo.setToken(token);
        userVo.setMenus(menuVOS);
        return ResultUtil.success(userVo);
    }

    @Transactional
    @Override
    public ResultUtil register(UserDTO userDTO) {
        String pwd = userDTO.getPassword();
        pwd = new BCryptPasswordEncoder().encode(pwd);
        userDTO.setPassword(pwd);
        int res = userMapper.register(userDTO);
        // 向user_role表中添加数据
        int res2 = roleMapper.addRoles(userMapper.selectUserByUsername(userDTO.getUsername()).getId(), RoleConstant.MEMBER);
        return (res > 0 && res2 > 0) ? ResultUtil.success() : ResultUtil.error("注册失败！");
    }

    @Override
    public ResultUtil<UserVO> selectUserById(long id) {
        User user = userMapper.selectById(id);
        UserVO userVo = BeanUtil.copyProperties(user, UserVO.class);
        userVo.setPassword("******");
        return ResultUtil.success(userVo);
    }

    @Override
    public ResultUtil updateById(UserDTO userDTO) {
        userDTO.setPassword(new BCryptPasswordEncoder().encode(userDTO.getPassword()));
        int result = userMapper.updateById(userDTO);
        return result > 0 ? ResultUtil.success() : ResultUtil.error("修改信息失败！");
    }

    @Override
    @Transactional
    public ResultUtil addUser(String ids, UserDTO userDTO) {
        User user = new User();
        BeanUtil.copyProperties(userDTO, user);
        user.setPassword(new BCryptPasswordEncoder().encode(user.getPassword()));
        user.setStatus(UserStatus.MEMBER_STATUS);
        int result = userMapper.insert(user);
        // 获取userId
        Long userId = user.getId();
        // 1、根据权限id为用户添加权限
//        List<Long> menuIds = Arrays.stream(ids.split(",")).map(Long::valueOf).collect(Collectors.toList());
        // 1.1、为角色绑定权限
//        menuIds.forEach(roleMapper::addMenus);
        // 1.2、为当前用户绑定Role
        roleMapper.addRoles(userId, RoleConstant.MEMBER);
        return result > 0 ? ResultUtil.success() : ResultUtil.error("添加失败！");
    }

    @Override
    public ResultUtil<List<Menu>> getMenus() {
        List<Menu> menus = menuMapper.getMenus();
        return ResultUtil.success(menus);
    }

    @Override
    public ResultUtil<PageResult<UserVO>> getUserList(UserPageDTO userPageDTO) {
        // 设置分页
        PageHelper.startPage(userPageDTO.getPage(), userPageDTO.getPageSize());
        Page<User> users = userMapper.pageQuery(userPageDTO);
        List<User> result = users.getResult();
        List<UserVO> userVos = new ArrayList<>(result.size());
        result.forEach(user -> {
            UserVO userVo = BeanUtil.copyProperties(user, UserVO.class);
            userVos.add(userVo);
        });
        return ResultUtil.success(new PageResult<>(users.getTotal(), userVos));
    }

    @Override
    @Transactional
    public ResultUtil deleteUserById(Long id) {
        // 如果该用户下有项目，则不能删除
        // 根据userid查询项目
        List<Project> projectList = projectMapper.selectProjectByUserId(id);
        if (!Objects.isNull(projectList) && !projectList.isEmpty()) {
            return ResultUtil.error("该用户下有管理的项目，不能删除");
        }
        int result = userMapper.deleteUserById(id);
        // 删除该用户对应的角色
        roleMapper.deleteRoleByUserId(id);
        return result > 0 ? ResultUtil.success() : ResultUtil.error("删除失败！");
    }

    @Override
    public ResultUtil<List<JobAndCountVO>> selectJobAndCount() {
        List<JobAndCountVO> jobAndCountVOList = userMapper.selectJobAndCount();
        Map<String, Integer> map = new HashMap<>();
        for (JobAndCountVO job : jobAndCountVOList) {
            if (map.containsKey(job.getName())) {
                map.put(job.getName(), map.get(job.getName()) + job.getValue());
            } else {
                map.put(job.getName(), job.getValue());
            }
        }
        jobAndCountVOList.clear();
        map.forEach((k, v) -> {
            jobAndCountVOList.add(JobAndCountVO.builder().name(k).value(v).build());
        });
        return ResultUtil.success(jobAndCountVOList);
    }

    @Override
    public ResultUtil<List<PermissionsVO>> getAuths() {
        List<Integer> statusList = userMapper.getAuths();
        List<PermissionsVO> permissionsVOList = new ArrayList<>();
        statusList.forEach(status -> {
            String name = "";
            if (status == 1) {
                name = "管理员";
            } else if (status == 2) {
                name = "项目负责人";
            } else if (status == 3) {
                name = "成员";
            }
            permissionsVOList.add(PermissionsVO.builder().id(status).name(name).build());
        });
        return ResultUtil.success(permissionsVOList);
    }

    @Override
    public ResultUtil authorization(Integer id, Integer authId) {
        int res = userMapper.authorization(id, authId);
        return res > 0 ? ResultUtil.success() : ResultUtil.error("赋权失败！");
    }

    @Override
    public ResultUtil<List<UserVO>> selectManager() {
        List<User> users = userMapper.selectManager();
        List<UserVO> userVOS = new ArrayList<>();
        users.forEach(user -> {
            userVOS.add(BeanUtil.copyProperties(user, UserVO.class));
        });
        return ResultUtil.success(userVOS);
    }
}
